refactor(guard): extract validateIntegrityField to eliminate triplicated switch blocks#4944
Conversation
…e switch blocks Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/aa47bbd9-ec09-410d-8b1d-a05c155849f6 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Refactors WASM guard policy validation by centralizing integrity-level (none|unapproved|approved|merged) checks into a single helper, reducing duplicated validation logic in the label-agent payload builder.
Changes:
- Added a new
validateIntegrityField(fieldName, raw)helper to validate integrity-level fields. - Replaced three duplicated integrity validation blocks in
buildStrictLabelAgentPayloadwith calls to the helper.
Show a summary per file
| File | Description |
|---|---|
internal/guard/wasm_validate.go |
Introduces shared integrity-level validation helper used by multiple policy fields. |
internal/guard/wasm_payload.go |
Uses the helper to validate integrity, disapproval-integrity, and endorser-min-integrity, removing duplicated switch blocks. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
| if err := validateIntegrityField("integrity", integrityRaw); err != nil { | ||
| return nil, err |
There was a problem hiding this comment.
The integrity validation error uses fieldName="integrity" even when the provided key was "min-integrity" (the preferred key). This can produce confusing errors for users supplying "min-integrity". Consider tracking which key was actually present (e.g., set a fieldName based on whether allowOnly["min-integrity"] or allowOnly["integrity"] was used) and pass that to validateIntegrityField so the error message matches the input field name.
| // validateIntegrityField returns an error if raw is not a valid integrity-level | ||
| // string. fieldName is used in the error message (e.g. "disapproval-integrity"). | ||
| func validateIntegrityField(fieldName string, raw interface{}) error { | ||
| s, ok := raw.(string) | ||
| if !ok { | ||
| return fmt.Errorf("invalid %s value: expected one of none|unapproved|approved|merged", fieldName) | ||
| } | ||
| switch strings.ToLower(strings.TrimSpace(s)) { | ||
| case "none", "unapproved", "approved", "merged": | ||
| return nil | ||
| default: | ||
| return fmt.Errorf("invalid %s value: expected one of none|unapproved|approved|merged", fieldName) | ||
| } |
There was a problem hiding this comment.
validateIntegrityField still duplicates the allowed-values string in multiple places (the error message is repeated in both the type-assertion failure and default case, and the allowed values are also duplicated in the switch). To fully achieve the goal of “single source of truth” for integrity levels, consider centralizing the allowed values (e.g., a const/slice + helper to format the error) so adding a new integrity level requires changing it in only one place.
| // validateIntegrityField returns an error if raw is not a valid integrity-level | |
| // string. fieldName is used in the error message (e.g. "disapproval-integrity"). | |
| func validateIntegrityField(fieldName string, raw interface{}) error { | |
| s, ok := raw.(string) | |
| if !ok { | |
| return fmt.Errorf("invalid %s value: expected one of none|unapproved|approved|merged", fieldName) | |
| } | |
| switch strings.ToLower(strings.TrimSpace(s)) { | |
| case "none", "unapproved", "approved", "merged": | |
| return nil | |
| default: | |
| return fmt.Errorf("invalid %s value: expected one of none|unapproved|approved|merged", fieldName) | |
| } | |
| var allowedIntegrityLevels = []string{"none", "unapproved", "approved", "merged"} | |
| var allowedIntegrityLevelSet = map[string]struct{}{ | |
| "none": {}, | |
| "unapproved": {}, | |
| "approved": {}, | |
| "merged": {}, | |
| } | |
| func invalidIntegrityFieldError(fieldName string) error { | |
| return fmt.Errorf( | |
| "invalid %s value: expected one of %s", | |
| fieldName, | |
| strings.Join(allowedIntegrityLevels, "|"), | |
| ) | |
| } | |
| // validateIntegrityField returns an error if raw is not a valid integrity-level | |
| // string. fieldName is used in the error message (e.g. "disapproval-integrity"). | |
| func validateIntegrityField(fieldName string, raw interface{}) error { | |
| s, ok := raw.(string) | |
| if !ok { | |
| return invalidIntegrityFieldError(fieldName) | |
| } | |
| normalized := strings.ToLower(strings.TrimSpace(s)) | |
| if _, ok := allowedIntegrityLevelSet[normalized]; ok { | |
| return nil | |
| } | |
| return invalidIntegrityFieldError(fieldName) |
|
@copilot address the review feedback |
…e in error messages Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/e17d0df0-3b26-42a6-82ce-cd488a8c8b44 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Done in d1461dd. Two changes made:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot address the review feedback |
The integrity-level validation switch (
none|unapproved|approved|merged) was inlined identically three times inbuildStrictLabelAgentPayload, meaning any new integrity level required three synchronized edits.Changes
internal/guard/wasm_validate.go(new): singlevalidateIntegrityField(fieldName string, raw interface{}) errorhelper — handles both thestringtype assertion and the validity switch in one placeinternal/guard/wasm_payload.go: replaces the three duplicate blocks forintegrity,disapproval-integrity, andendorser-min-integritywith calls to the helperWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
example.com/tmp/go-build3106413706/b513/launcher.test /tmp/go-build3106413706/b513/launcher.test -test.testlogfile=/tmp/go-build3106413706/b513/testlog.txt -test.paniconexit0 -test.timeout=10m0s -o .cfg 3753103/b314/ x_amd64/vet -p github.com/githu--version -lang=go1.25 x_amd64/vet .cfg�� 3753103/b364/_pkg_.a ache/go/1.25.9/x64/src/net/http/internal/httpcommon/httpcommon.ggoogle.golang.org/protobuf/types-qE x_amd64/vet --gdwarf-5 --64 -o 42W3fCn/gP4cHa5aRI3EQQAZUMxk(dns block)invalid-host-that-does-not-exist-12345.com/tmp/go-build3106413706/b495/config.test /tmp/go-build3106413706/b495/config.test -test.testlogfile=/tmp/go-build3106413706/b495/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build3106413706/b393/vet.cfg 1.80.0/resolver/dns/dns_resolver.go 64/src/crypto/x509/cert_pool.go x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet -o g_.a -trimpath x_amd64/vet -p gzip -lang=go1.25 x_amd64/vet(dns block)nonexistent.local/tmp/go-build3106413706/b513/launcher.test /tmp/go-build3106413706/b513/launcher.test -test.testlogfile=/tmp/go-build3106413706/b513/testlog.txt -test.paniconexit0 -test.timeout=10m0s -o .cfg 3753103/b314/ x_amd64/vet -p github.com/githu--version -lang=go1.25 x_amd64/vet .cfg�� 3753103/b364/_pkg_.a ache/go/1.25.9/x64/src/net/http/internal/httpcommon/httpcommon.ggoogle.golang.org/protobuf/types-qE x_amd64/vet --gdwarf-5 --64 -o 42W3fCn/gP4cHa5aRI3EQQAZUMxk(dns block)slow.example.com/tmp/go-build3106413706/b513/launcher.test /tmp/go-build3106413706/b513/launcher.test -test.testlogfile=/tmp/go-build3106413706/b513/testlog.txt -test.paniconexit0 -test.timeout=10m0s -o .cfg 3753103/b314/ x_amd64/vet -p github.com/githu--version -lang=go1.25 x_amd64/vet .cfg�� 3753103/b364/_pkg_.a ache/go/1.25.9/x64/src/net/http/internal/httpcommon/httpcommon.ggoogle.golang.org/protobuf/types-qE x_amd64/vet --gdwarf-5 --64 -o 42W3fCn/gP4cHa5aRI3EQQAZUMxk(dns block)this-host-does-not-exist-12345.com/tmp/go-build3106413706/b522/mcp.test /tmp/go-build3106413706/b522/mcp.test -test.testlogfile=/tmp/go-build3106413706/b522/testlog.txt -test.paniconexit0 -test.timeout=10m0s -I .cfg -I x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet .cfg�� 3753103/b400/_pkg_.a -dynimport x_amd64/vet -dynout g/grpc/internal//usr/bin/runc p/bin/git x_amd64/vet(dns block)If you need me to access, download, or install something from one of these locations, you can either: